package cn.yzgy.yzgyoa.common.report;

import cn.yzgy.yzgyoa.common.entity.SysAlarm;
import cn.yzgy.yzgyoa.common.utils.TimeUtil;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * EXCEL生成类，用于生成excel文档
 *
 * @author Yqsen
 * @since 2020-09-10 11:25:56
 */
public class ExcelGen<T> {

    private final static String COPYRIGHT_STR = "由 重庆钰圳广越商贸有限公司 运营管理平台YZGY-OA. 生成";
    public final static String AUTOINCREMENT_COLUMN_IDENTIFIER = "AUTO_INCREMENT";
    private final static String DEFAULT_SHEET_NAME = "数据";

    private final List<ExcelGenColConfig> colConfig;
    private final ExcelGenConfig genConfig;
    private final List<T> data;

    public ExcelGen(ExcelGenConfig genConfig, List<ExcelGenColConfig> colConfig, List<T> data) {
        this.genConfig = genConfig;
        this.colConfig = colConfig;
        this.data = data;
    }

    public ReportGenResult createReport() {
        File file = new File(genConfig.getFilePath());
        OutputStream outputStream;
        try {
            outputStream = new FileOutputStream(new File(file, genConfig.getFileName()));
            getWorkBook().write(outputStream);
            outputStream.flush();
            outputStream.close();

        } catch (IOException e) {
            new SysAlarm().setErrDesc(String.format("LocalMessage:%s \n Message:%s \n Cause:%s",
                    e.getLocalizedMessage(), e.getMessage(), e.getCause())).insert(3);
            return new ReportGenResult().setSuccess(false).setErrDesc(e.getMessage());
        }

        return new ReportGenResult().setSuccess(true)
                .setFileName(genConfig.getFileName())
                .setFilePath(genConfig.getFilePath())
                .setFullPath(genConfig.getFilePath() + genConfig.getFileName());
    }

    public HSSFWorkbook getWorkBook(){
        HSSFWorkbook curBook = new HSSFWorkbook();
        Sheet sheet = curBook.createSheet(DEFAULT_SHEET_NAME);
        sheet.protectSheet("");

        int i = 0;
        // 创建主标题
        CellRangeAddress region = new CellRangeAddress(i, i, 0, colConfig.size() - 1);
        Row title = sheet.createRow(i);
        title.setHeight((short) (20 * 40));
        sheet.addMergedRegion(region);
        Cell titleCell = title.createCell(0);
        titleCell.setCellStyle(getTitleStyle(curBook));
        titleCell.setCellValue(genConfig.getDocumentTitle());
        addRegionBorder(BorderStyle.THIN, region, sheet);

        // 创建副标题
        i++;
        CellRangeAddress region2 = new CellRangeAddress(i, i, 0, colConfig.size() - 1);
        Row title2 = sheet.createRow(i);
        title2.setHeight(getSecondTitleHeight(genConfig.getSecondTitle()));
        sheet.addMergedRegion(region2);
        Cell titleCell2 = title2.createCell(0);
        titleCell2.setCellStyle(getSecondTitleStyle(curBook));
        titleCell2.setCellValue(new HSSFRichTextString(genConfig.getSecondTitle()));
        addRegionBorder(BorderStyle.THIN, region2, sheet);

        // 创建列名列
        Row colNameCol = sheet.createRow(++i);
        for (int j = 0; j < colConfig.size(); j++) {
            ExcelGenColConfig curColConfig = colConfig.get(j);
            // 设置列宽
            sheet.setColumnWidth(j, (curColConfig.getColWidth() * 256));
            Cell tCell = colNameCol.createCell(j);
            tCell.setCellStyle(getColNameRowStyle(curBook));
            tCell.setCellValue(curColConfig.getTitleName());
        }

        // 设置冻结窗格
        sheet.createFreezePane(0, ++i);

        // 填充数据域
        int no = 1;
        CellStyle dataCellStyle = getBasicCellStyle(curBook);
        for (Object objData : data) {
            Row dataRow = sheet.createRow(i++);
            Field[] fields = objData.getClass().getDeclaredFields();
            for (int k = 0; k < colConfig.size(); k++) {
                ExcelGenColConfig curColConfig = colConfig.get(k);
                Cell cell = dataRow.createCell(k);
                cell.setCellStyle(dataCellStyle);
                if (curColConfig.getFieldName().equals(AUTOINCREMENT_COLUMN_IDENTIFIER)) {
                    cell.setCellValue(no++);
                    continue;
                }
                setCellValue(curColConfig, cell, getFieldValue(curColConfig.getFieldName(), fields, objData));
            }
        }

        // 最后一行
        Row finalRow = sheet.createRow(i);
        finalRow.setHeight((short) (20 * 20));
        CellRangeAddress region3 = new CellRangeAddress(i, i, 0, colConfig.size() - 1);
        sheet.addMergedRegion(region3);
        Cell finalCell = finalRow.createCell(0);
        // 最后一行的样式
        HSSFCellStyle lastItemStyle = curBook.createCellStyle();
        lastItemStyle.setAlignment(HorizontalAlignment.LEFT);
        lastItemStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        finalCell.setCellStyle(lastItemStyle);
        finalCell.setCellValue(COPYRIGHT_STR);

        return curBook;
    }

    /**
     * 设置单元格的值，根据列定义中定义的列数据类型，设定单元格类型，目前支持：文本，时间，数值
     * @param colConfig 列配置
     * @param cell 要设置值的单元格
     * @param obj 数据对象
     */
    private void setCellValue(ExcelGenColConfig colConfig, Cell cell, Object obj) {
        if ("".equals(colConfig.getDataType())) {
            cell.setCellValue(obj.toString());
            return;
        }
        if (BigDecimal.class.getName().equals(colConfig.getDataType())) {
            BigDecimal t = (BigDecimal) obj;
            cell.setCellValue(t.doubleValue());
            return;
        }
        if (LocalDateTime.class.getName().equals(colConfig.getDataType())) {
            LocalDateTime t = (LocalDateTime) obj;
            cell.setCellValue(t.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            return;
        }
        if (Date.class.getName().equals(colConfig.getDataType())) {
            Date t = (Date) obj;
            cell.setCellValue(TimeUtil.getSimpleDateFormat().format(t));
            return;
        }
        cell.setCellValue(obj.toString());
    }

    private short getSecondTitleHeight(String str) {
        int count = 0;
        int pos = -1;
        boolean flag;
        while (true) {
            pos = str.indexOf("\r\n", pos + 1);
            if (pos != -1){
                count++;
            }else{
                break;
            }
        }
        return (short) (count * 20 * 30);
    }

    private void addRegionBorder(BorderStyle borderStyle, CellRangeAddress range, Sheet sheet) {
        RegionUtil.setBorderBottom(borderStyle, range, sheet);
        RegionUtil.setBorderTop(borderStyle, range, sheet);
        RegionUtil.setBorderLeft(borderStyle, range, sheet);
        RegionUtil.setBorderRight(borderStyle, range, sheet);
    }

    /**
     * 获取某列的值
     *
     * @param fieldName 列明
     * @param fields 对象的属性列表
     * @param obj 对象
     * @return 该列的值
     */
    private Object getFieldValue(String fieldName, Field[] fields, Object obj) {
        for (Field x : fields) {
            x.setAccessible(true);
            if (x.getName().equals(fieldName)) {
                try {
                    Object resObj = x.get(obj);
                    return resObj == null ? "" : resObj;
                } catch (IllegalAccessException e) {
                    return "#ERROR_COL_NAME";
                }
            }
        }
        return "";
    }

    /**
     * 创建副标题单元格的样式
     * @param workbook workbook
     * @return 副标题样式
     */
    private HSSFCellStyle getSecondTitleStyle(HSSFWorkbook workbook) {
        HSSFCellStyle style = getBasicCellStyle(workbook);
        style.setAlignment(HorizontalAlignment.LEFT);
        style.setWrapText(true);
        HSSFFont font = workbook.createFont();
        style.setFont(font);
        return style;
    }


    /**
     * 创建标题行单元格的样式
     * @param workbook workbook
     * @return 标题行样式
     */
    private HSSFCellStyle getTitleStyle(HSSFWorkbook workbook) {
        HSSFCellStyle style = getBasicCellStyle(workbook);
        style.setAlignment(HorizontalAlignment.LEFT);
        HSSFFont font = workbook.createFont();
        font.setFontHeight((short) (25 * 10));
        style.setFont(font);
        return style;
    }

    /**
     * 创建列名行单元格的样式
     * @param workbook workbook
     * @return 列名行样式
     */
    private HSSFCellStyle getColNameRowStyle(HSSFWorkbook workbook) {
        HSSFCellStyle style = getBasicCellStyle(workbook);
        style.setFillBackgroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
        HSSFFont font = workbook.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short)10);
        style.setFont(font);
        return style;
    }

    /**
     * 创建数据行单元格的样式
     * @param workbook workbook
     * @return 数据行样式
     */
    private HSSFCellStyle getBasicCellStyle(HSSFWorkbook workbook) {
        HSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        return style;
    }
}
